#ifndef __M_EXCHANGE_H__
#define __M_EXCHANGE_H__

#include "../mqcommon/logger.hpp"
#include "../mqcommon/helpper.hpp"
#include "../mqcommon/msg.pb.h"

#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>

namespace mmq
{

    // 1. 交换机本身属性
    struct Exchange
    {
    public:
        using ptr = std::shared_ptr<Exchange>;

    public:
        Exchange() {}
        Exchange(const std::string &name, ExchangeType type, bool durable, bool auto_delete,
                const google::protobuf::Map<std::string, std::string> &args)
            : _name(name), _type(type), _durable(durable), _auto_delete(auto_delete), _args(args)
        {
        }

        // args存储键值对，在存储数据库时，会组织一个格式字符串进行存储 key=val&key=val&key=val...
        // 内部解析str_args，将内容存储到_args成员中
        void SetArgs(const std::string &str_args)
        {
            // key=val&key=val&
            std::vector<std::string> result;
            StrHelper::Split(str_args, "&", result);
            for (auto &str : result)
            {
                size_t pos = str.find('=');
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                // _args.insert({key, val});
                _args[key] = val;
            }
        }

        // 将成员_args中的内容序列化后，返回一个字符串
        std::string GetArgs()
        {
            std::string ret;
            for (auto it = _args.begin(); it != _args.end(); ++it)
            {
                ret += it->first + "=" + it->second + "&";
            }
            // for(auto &[k, v] : _args)
            // {
            //     ret += k + "=" + v + "&";
            // }
            return ret;
        }

    public:
        std::string _name;                                  // 名称
        mmq::ExchangeType _type;                            // 类型
        bool _durable;                                      // 是否持久化
        bool _auto_delete;                                  // 是否自动删除
        // std::unordered_map<std::string, std::string> _args; // 其它参数
        google::protobuf::Map<std::string, std::string> _args;
    };


    // 2. 定义交换机数据持久化管理类-----数据存储在sqlite数据库中
    using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
    class ExchangeMapper
    {
    public:
        ExchangeMapper(const std::string &dbfile) : _sql_helper(dbfile)
        {
            // 创建父目录结构
            std::string pPath = FileHelper::ParentDirectory(dbfile);
            FileHelper::CreateDirectory(pPath);
            // 创建/打开数据库
            assert(_sql_helper.Open());
            CreateTable();
        }

        // 创建交换机表单
        void CreateTable()
        {
            std::stringstream ss;
            ss << "create table if not exists exchange_table(";
            ss << "name varchar(32) primary key, ";
            ss << "type int, ";
            ss << "durable int, ";
            ss << "auto_delete int, ";
            ss << "args varchar(128));";
            assert(_sql_helper.Exec(ss.str(), nullptr, nullptr));
        }

        // 删除表单
        void RemoveTable()
        {
            std::string sql = "drop table if exists exchange_table;";
            bool ret = _sql_helper.Exec(sql, nullptr, nullptr);
            if (ret == false)
            {
                DLOG("删除交换机数据库表失败! ");
                abort();
            }
        }

        // 向表中插入交换机数据
        bool Insert(Exchange::ptr &exp)
        {
            std::stringstream ss;
            ss << "insert into exchange_table values(";
            ss << "'" << exp->_name << "', ";
            ss << "'" << exp->_type << "', ";
            ss << "'" << exp->_durable << "', ";
            ss << "'" << exp->_auto_delete << "', ";
            ss << "'" << exp->GetArgs() << "');";
            return _sql_helper.Exec(ss.str(), nullptr, nullptr);
        }

        // 删除表中某个交换机数据
        void Remove(const std::string &name)
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "';";
            _sql_helper.Exec(ss.str(), nullptr, nullptr);
        }

        // 恢复交换机数据
        ExchangeMap Recovery()
        {
            std::string sql = "select name, type, durable, auto_delete, args from exchange_table;";
            ExchangeMap result;
            _sql_helper.Exec(sql, SelectCallback, &result);
            return result;
        }

    private:
        static int SelectCallback(void *arg, int colnum, char **row, char **fields)
        {
            ExchangeMap *result = (ExchangeMap *)arg;
            auto exp = std::make_shared<Exchange>();
            exp->_name = row[0];
            exp->_type = (ExchangeType)std::stoi(row[1]);
            exp->_durable = (bool)std::stoi(row[2]);
            exp->_auto_delete = (bool)std::stoi(row[3]);
            if (row[4])
                exp->SetArgs(row[4]);
            result->insert({exp->_name, exp});
            return 0;
        }

    private:
        mmq::SqliteHelper _sql_helper; // 数据库管理句柄
    };

    // 3. 定义交换机内存管理类(这个才是真正的交换机对外数据管理类)
    class ExchangeManager
    {
    public:
        using ptr = std::shared_ptr<ExchangeManager>;

    public:
        ExchangeManager(const std::string &dbfile) : _mapper(dbfile)
        {
            _exchanges = _mapper.Recovery();
        }

        // 声明交换机
        bool DeclareExchange(const std::string &name, mmq::ExchangeType type, bool durable,
                bool auto_delete, const google::protobuf::Map<std::string, std::string> &args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 判断交换机是否存在(不直接调用Exists是因为Exists内部也加了锁，调用会导致死锁)
            auto it = _exchanges.find(name);
            if (it != _exchanges.end())
            {
                return true;
            }
            // 构造并插入Exchange共享指针
            auto exp = std::make_shared<Exchange>(name, type, durable, auto_delete, args);
            if (exp->_durable == true)
            {
                bool ret =  _mapper.Insert(exp);
                if(ret == false) return false;
            }
            _exchanges.insert({exp->_name, exp});
            return true;
        }

        // 删除交换机
        void DeleteExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 判断交换机是否存在
            auto it = _exchanges.find(name);
            if (it == _exchanges.end())
            {
                return;
            }
            // 存在则删除
            if (_exchanges[name]->_durable == true)
            {
                _mapper.Remove(name);
            }
            _exchanges.erase(name);
        }

        // 获取指定交换机对象
        Exchange::ptr SelectExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 判断交换机是否存在
            auto it = _exchanges.find(name);
            if (it == _exchanges.end())
            {
                return Exchange::ptr();
            }
            return it->second;
        }

        // 判断交换机是否存在
        bool Exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end())
            {
                return false;
            }
            return true;
        }

        // 返回_exchanges的交换机的数量
        size_t Size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchanges.size();
        }

        // 清理所有交换机数据
        void Clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.RemoveTable();
            _exchanges.clear();
        }

    private:
        std::mutex _mutex;
        ExchangeMapper _mapper;
        ExchangeMap _exchanges;
    };

}
#endif